package com.swt.gap.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.swt.gap.common.NodeTypeEnum;
import com.swt.gap.common.PageResult;
import com.swt.gap.common.PermissionService;
import com.swt.gap.common.graph.Graph;
import com.swt.gap.common.graph.GraphProcessor;
import com.swt.gap.dao.*;
import com.swt.gap.model.entity.*;
import com.swt.gap.model.vo.ResultStatisticsVO;
import com.swt.gap.model.vo.achievementcenter.*;
import com.swt.gap.model.vo.AchievementInfoVO;
import com.swt.gap.service.AchievementService;
import com.swt.gap.service.SysGroupService;
import com.swt.gap.util.UserLoginUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tyh
 * @date 2020/5/11 19:29
 */

@Service
@Slf4j
public class AchievementServiceImpl implements AchievementService {

    private final AchievementDao achievementDao;
    private final TaskResultMapper taskResultMapper;
    private final SysUserMapper userMapper;
    private final GraphProcessor graphProcessor;
    private final SysGroupService sysGroupService;
    private final PermissionService permissionService;

    public AchievementServiceImpl(AchievementDao achievementDao,
                                  TaskResultMapper taskResultMapper,
                                  SysUserMapper userMapper,
                                  GraphProcessor graphProcessor,
                                  SysGroupService sysGroupService,
                                  PermissionService permissionService) {
        this.achievementDao = achievementDao;
        this.taskResultMapper = taskResultMapper;
        this.userMapper = userMapper;
        this.graphProcessor = graphProcessor;
        this.sysGroupService = sysGroupService;
        this.permissionService = permissionService;
    }

    @Override
    public Boolean judgeName(Integer userId,String achievementName, Integer achievementId) {
        //指定用户下查询同名，另外如果是修改的话，还需要排除该战果自身

        Achievement record = achievementDao.selectByName(achievementName, userId);
        if(record == null){
            return false;
        }
        if(achievementId != null){
            return !achievementId.equals(record.getAchievementId());
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addAchievement(int userId,AddOrUpdateAchievementModel addOrUpdateAchievementModel) {
        Achievement achievement = new Achievement();
        achievement.setAchievementId(null);
        achievement.setAchievementName(addOrUpdateAchievementModel.getAchievementName());
        achievement.setDescription(addOrUpdateAchievementModel.getDescription());
        achievement.setContent(addOrUpdateAchievementModel.getContent());
        achievement.setCreatedBy(userId);
        achievement.setCreatedTime(new Date());
        achievement.setUpdateTime(new Date());
        achievement.setIsDeleted(false);
        achievement.setIsPublished(false);
        achievement.setSpaceVal(addOrUpdateAchievementModel.getSpaceVal());
        achievement.setAchievementClassId(addOrUpdateAchievementModel.getAchievementClassId());
        achievement.setPassword(addOrUpdateAchievementModel.getPassword());
        achievementDao.insertSelective(achievement);

        return achievement.getAchievementId();
    }

    @Override
    public int updateAchievement(AddOrUpdateAchievementModel addOrUpdateAchievementModel) {
        Achievement achievement = new Achievement();
        achievement.setAchievementId(addOrUpdateAchievementModel.getAchievementId());
        achievement.setAchievementName(addOrUpdateAchievementModel.getAchievementName());
        achievement.setContent(addOrUpdateAchievementModel.getContent());
        achievement.setDescription(addOrUpdateAchievementModel.getDescription());
        achievement.setUpdateTime(new Date());
        achievement.setSpaceVal(addOrUpdateAchievementModel.getSpaceVal());
        achievement.setAchievementClassId(addOrUpdateAchievementModel.getAchievementClassId());
        achievement.setPassword(addOrUpdateAchievementModel.getPassword());
        return achievementDao.updateByPrimaryKeySelective(achievement);
    }

    @Override
    public AchievementInfoVO getAchievementInfo(Integer achievementId) {
        Integer loginUserId = UserLoginUtils.getUserId();

        AchievementInfoVO achievementInfoVO = new AchievementInfoVO();
        Achievement achievement = achievementDao.selectByPrimaryKey(achievementId);

        BeanUtils.copyProperties(achievement, achievementInfoVO);
        SysUser sysUser = userMapper.selectByPrimaryKey(achievement.getCreatedBy());
        achievementInfoVO.setCreatedName(sysUser.getUserName());

//        List<TaskResultWithBLOBs> taskResultWithBLOBs = new ArrayList<>();
//        List<AchievementTastResult> achievementTaskResults = achievementTastResultMapper.selectByAchievementId(achievementId);
//        for (AchievementTastResult achievementTastResult : achievementTaskResults) {
//            TaskResultWithBLOBs resultWithBLOBs = taskResultMapper.selectByPrimaryKey(achievementTastResult.getResultId());
//            taskResultWithBLOBs.add(resultWithBLOBs);
//        }
//        achievementInfoVO.setTaskResultWithBLOBs(taskResultWithBLOBs);

        achievementInfoVO.setHasReadPermission(permissionService.hasReadPerm(loginUserId,
                achievement.getCreatedBy(), achievement.getPassword()));
        achievementInfoVO.setHasWritePermission(permissionService.hasWritePerm(loginUserId, achievement.getCreatedBy()));
        achievementInfoVO.setHasPassword(!StringUtils.isEmpty(achievement.getPassword()));
        achievementInfoVO.setPassword(null);
        return achievementInfoVO;
    }

    /*@Override
    public AchievementCenterIndexVO getAchievementList(int userId,String keyword) {
        long currentTimeMillis = System.currentTimeMillis();
        //1、查出用户所有的战果
        List<TinyAchievementInfoVO> tinyAchievementInfo = achievementDao.selectByUserAndKeyword(userId,keyword);

        long latelyWeekTimestamp = currentTimeMillis - 7 * 24 * 60 * 60 * 1000L;
        long latelyMonthTimestamp = currentTimeMillis - 30 * 24 * 60 * 60 * 1000L;

        //2、创建三个集合，用于存三个时间区间的数据（最近一周是以当前时间往前推7天，最近一个月就是以七天之前，到当前天往前推30天之间，更早之前：30天之前的）
        List<TinyAchievementInfoVO> latelyWeekAchievementInfos = new ArrayList<>();
        List<TinyAchievementInfoVO> latelyMonthAchievementInfos = new ArrayList<>();
        List<TinyAchievementInfoVO> earlierAchievementInfos = new ArrayList<>();

        AchievementCenterIndexVO achievementCenterIndexVO = new AchievementCenterIndexVO();
        //3、遍历战果列表，并将符合要求的数据存入到三个集合中
        if (tinyAchievementInfo != null && tinyAchievementInfo.size() > 0){

            tinyAchievementInfo.forEach(x->{
                long createTimestamp = x.getCreateTime().getTime();
                if(createTimestamp >= latelyWeekTimestamp){
                    latelyWeekAchievementInfos.add(x);
                }else if(latelyWeekTimestamp > createTimestamp && latelyMonthTimestamp <= createTimestamp){
                    latelyMonthAchievementInfos.add(x);
                }else {
                    earlierAchievementInfos.add(x);
                }

            });

            achievementCenterIndexVO.setLatelyWeekData(latelyWeekAchievementInfos);
            achievementCenterIndexVO.setLateLyMonthData(latelyMonthAchievementInfos);
            achievementCenterIndexVO.setEarlierData(earlierAchievementInfos);

        }

        //4、封装结果，并返回数据

        return achievementCenterIndexVO;
    }
*/
    @Override
    public PageResult<TinyAchievementInfoVO> searchAchievement(int userId, String keyword, int orderType, int pageNum, int pageSize) {
        if(pageSize == 0){
            pageSize = 10;
        }
        if (0 != pageNum) {
            PageHelper.startPage(pageNum, pageSize);
        }

        Page<TinyAchievementInfoVO> tinyAchievementInfos = achievementDao.searchAchievement(userId,keyword,orderType);


        return new PageResult<>(tinyAchievementInfos);
    }

    @Override
    public int deleteAchievement(int[] achievementIds) {

        return achievementDao.banchDelete(achievementIds);
    }

    @Override
    public List<AchievementListVO> listAchievement(Integer userId, String keyword) {
        List<AchievementListVO> retValue = new ArrayList<>();
        List<Integer> userIds = sysGroupService.listSameGroupUserByUserId(userId);
        List<TinyAchievementInfoVO> achievements = achievementDao.selectByUserAndKeyword(userIds, keyword);
        Map<String, List<TinyAchievementInfoVO>> mapAchievement = achievements.stream()
                .collect(Collectors.groupingBy(a -> a.getAchievementClassId() + "@" + a.getAchievementClass()));
        mapAchievement.forEach((k,v) -> {
            String[] achievementClass = k.split("@");
            AchievementListVO achievement = AchievementListVO.builder()
                    .achievementClassId(Integer.parseInt(achievementClass[0]))
                    .achievementClass(achievementClass[1])
                    .achievements(v)
                    .build();
            retValue.add(achievement);
        });
        retValue.sort(Comparator.comparing(AchievementListVO::getAchievementClassId).reversed());
        return retValue;
    }

    @Override
    public List<ResultStatisticsVO> statisticsResult(String field, Integer resultId) {
        List<ResultStatisticsVO> retValue = new ArrayList<>();
        TaskResultWithBLOBs taskResult = taskResultMapper.selectByPrimaryKey(resultId);
        List<Graph.Node> nodes = new ArrayList<>();
        switch (taskResult.getType()) {
            case 1:
                nodes = JSON.parseObject(taskResult.getContent(), Graph.class).getNodes();
                break;
            case 2:
                nodes = JSON.parseArray(taskResult.getContent(), Graph.Node.class);
                break;
            default:
                break;
        }
        Map<String, Integer> mapCount = new HashMap<>();
        if ("事件类型".equals(field)) {
            nodes.forEach(node -> {
                if (node.getLabels().contains("事件")) {
                    mapCount.merge(node.getLabels().get(1), 1, Integer::sum);
                }
            });
        } else {
            nodes.forEach(node -> {
                if (node.getLabels().contains(field)) {
                    String nodeId = node.getId();
                    String cypher = "match (n)--(m:" + NodeTypeEnum.EVENT.getName() + ") where n.id = '" + nodeId + "' return count(m) as num";

                    Integer count = graphProcessor.executeReadCypherReturnNum(cypher).intValue();
                    mapCount.merge(node.getName(), count, Integer::sum);
                }
            });
        }
        mapCount.forEach((k,v) -> {
            ResultStatisticsVO resultStatistics = ResultStatisticsVO.builder()
                    .fieldValue(k).number(v.doubleValue()).build();
            retValue.add(resultStatistics);
        });
        return retValue;
    }

    @Override
    public PageResult<AchievementInfoListVO> listAchievement3(Integer userId, String keyword, Integer pageNum, Integer pageSize) {
        List<AchievementInfoListVO> retValue = new ArrayList<>();
        List<Integer> userIds = sysGroupService.listSameGroupUserByUserId(userId);
        if(null != pageNum && pageNum > 0 && null != pageSize && pageSize > 0) {
            PageHelper.startPage(pageNum, pageSize);
        } else {
            pageNum = 0;
            pageSize = 0;
        }

        Page<Achievement> achievements = achievementDao.selectByUserAndKeywordNoClass(userIds, keyword);

        achievements.getResult().forEach(a -> {
            AchievementInfoListVO al = new AchievementInfoListVO();
            BeanUtils.copyProperties(a, al);
            al.setHasReadPermission(permissionService.hasReadPerm(userId, a.getCreatedBy(), a.getPassword()));
            al.setHasWritePermission(permissionService.hasWritePerm(userId, a.getCreatedBy()));
            al.setHasPassword(!StringUtils.isEmpty(a.getPassword()));
            al.setCreatorRealName(userMapper.selectByPrimaryKey(a.getCreatedBy()).getRealName());
            retValue.add(al);
        });
        return new PageResult<>(retValue, (int)achievements.getTotal(), pageSize, pageNum);
    }

    @Override
    public Boolean hasWritePermission(Integer userId, Integer achievementId) {
        boolean retValue = false;
        Achievement achievement = achievementDao.selectByPrimaryKey(achievementId);
        if (null != achievement && null != achievement.getCreatedBy()) {
            retValue = permissionService.hasWritePerm(userId, achievement.getCreatedBy());
        }
        return retValue;
    }

    @Override
    public Integer updatePassword(AchievementPassword achievementPassword) {
        if (!StringUtils.isEmpty(achievementPassword.getPassword())) {
            achievementPassword.setPassword(SecureUtil.md5(achievementPassword.getPassword()));
        }
        return achievementDao.updatePassword(achievementPassword.getPassword(), achievementPassword.getAchievementIds());
    }

    @Override
    public Boolean getReadPerm(Integer achievementId, String password) {
        boolean flag = false;
        Integer userId = UserLoginUtils.getUserId();
        Achievement achievement = achievementDao.selectByPrimaryKey(achievementId);
        if(null != achievement) {
            if (permissionService.hasReadPerm(userId, achievement.getCreatedBy(), achievement.getPassword())) {
                flag = true;
            } else {
                String inputPassword = SecureUtil.md5(password);
                flag = inputPassword.equals(achievement.getPassword());
            }
        }
        return flag;
    }


}
